#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <experimental/filesystem>
#include <vector>
#include <jsoncpp/json/json.h>
#include <memory>
#include "bundle.h"

namespace cloud
{
  class FileUtil
  {
  private:
    std::string _file_name; //文件path
  public:
    //默认构造
    FileUtil(const std::string& file_name)
      : _file_name(file_name)
    {}
    
    //获取文件大小
    int64_t FileSize()
    {
      struct stat st;
      //获取失败
      if(stat(_file_name.c_str(), &st) < 0)
      {
        std::cout << "FileSize() is fail." << std::endl;
        return -1;
      }
      return st.st_size;
    }

    //获取最后修改时间
    time_t LastMTime()
    {
      struct stat st;
      //获取失败
      if(stat(_file_name.c_str(), &st) < 0)
      {
        std::cout << "LastMTime() is fail." << std::endl;
        return -1;
      }
      return st.st_mtime;
    }

    //获取最后访问时间
    time_t LastATime()
    {
      struct stat st;
      //获取失败
      if(stat(_file_name.c_str(), &st) < 0)
      {
        std::cout << "LastATime() is fail." << std::endl;
        return -1;
      }
      return st.st_atime;
    }

    //文件名--/xxx/xxx/test.cpp 即获取test.cpp，不包含路径
    std::string FileName()
    {
      size_t pos = _file_name.find_last_of("/"); //找到path中的最后一个'/'的下标
      if(pos == std::string::npos)
      {
        return _file_name;
      }
      return _file_name.substr(pos + 1);
    }
    
    //删除一个文件
    bool Remove()
    {
      if(Exists() == false)
      {
        std::cout << "Remove() nothing to do." << std::endl;
        return true;
      }
      std::cout << "rmove" << std::endl;
      remove(_file_name.c_str());
      return true;
    }

    //获取从pos位置开始长度为len的内容
    bool GetPosLen(std::string& body, int pos, int len)
    {
      //请求内容超过文件总大小
      if(pos + len > FileSize())
      {
        std::cout << "The requested content exceeds the total file size." << std::endl;
        return false;
      }
      std::ifstream ifs;
      ifs.open(_file_name, std::ios::binary); //打开文件
      //打开文件失败
      if(ifs.is_open() == false)
      {
        std::cout << "Fail to open file." << std::endl;
        ifs.close();
        return false;
      }
      ifs.seekg(pos, std::ios::beg); //将文件指针偏移到pos位置
      body.resize(len);
      ifs.read(&body[0], len); //读取数据
      //读取失败
      if(ifs.good() == false)
      {
        std::cout << "Write failed." << std::endl;
        ifs.close();
        return false;
      }
      ifs.close();
      return true;
    }
    
    //获取文件全部内容
    bool GetFileContent(std::string& body)
    {
      GetPosLen(body, 0, FileSize());
      return true;
    }

    //向文件写入内容
    bool SetFileContent(const std::string& body)
    {
      std::ofstream ofs;
      ofs.open(_file_name, std::ios::binary);
      if(ofs.is_open() == false)
      {
        std::cout << "Fail to open file." << std::endl;
        ofs.close();
        return false;
      }
      ofs.write(&body[0], body.size()); //写入数据
      //写入失败
      if(ofs.good() == false)
      {
        std::cout << "Read failed" << std::endl;
        ofs.close();
        return false;
      }
      ofs.close();
      return true;
    }

    //压缩
    bool Compress(const std::string& file_name)
    {
      std::string body;
      //获取需要压缩的文件的内容
      if(GetFileContent(body) == false)
      {
        std::cout << "Compress() error." << std::endl;
        return false;
      }
      std::string packed = bundle::pack(bundle::LZIP, body); //进行压缩
      FileUtil fu(file_name);
      //将内容写入file_name
      if(fu.SetFileContent(packed) == false)
      {
        std::cout << "Compress() error." << std::endl;
        return false;
      }
      return true;
    }

    //解压缩
    bool UnCompress(const std::string& file_name)
    {
      std::string body;
      //获取文件内容
      if(GetFileContent(body) == false)
      {
        std::cout << "UnCompress() error." << std::endl;
        return false;
      }
      
      std::string unpacked = bundle::unpack(body);
      FileUtil fu(file_name);
      //将获取到的解压内容设置进file_name文件
      if(fu.SetFileContent(unpacked) == false)
      {
        std::cout << "UnCompress() error." << std::endl;
        return false;
      }
      return true;
    }

    //判断文件是否存在
    bool Exists()
    {
      return std::experimental::filesystem::exists(_file_name);
    }

    //创建目录
    bool CreateDirectory()
    {
      if(std::experimental::filesystem::exists(_file_name))
      {
        return false;
      }
      return std::experimental::filesystem::create_directories(_file_name);
    }

    //获取目录下的文件,以相对路径的形式返回
    bool ScanDirectory(std::vector<std::string>& arr)
    {
      for(auto& p : std::experimental::filesystem::directory_iterator(_file_name))
      {
        //如果该元素是一个目录不输出
        if(std::experimental::filesystem::is_directory(p))
        {
          continue;
        }
        arr.push_back(std::experimental::filesystem::path(p).relative_path().string());
      }
      return true;
    }
  };

  class JsonUtil
  {
  public:
    //序列化
    static bool Serialize(const Json::Value& root, std::string& str)
    {
      Json::StreamWriterBuilder swb;
      std::unique_ptr<Json::StreamWriter> sw_ptr(swb.newStreamWriter());
      std::stringstream ss;
      sw_ptr->write(root, &ss);
      str = ss.str();
      return true;
    }
    
    //反序列化
    static bool UnSerialize(const std::string& str, Json::Value& root)
    {
      Json::CharReaderBuilder crb;
      std::unique_ptr<Json::CharReader> cr_ptr(crb.newCharReader());
      std::string err;
      bool ret = cr_ptr->parse(str.c_str(), str.c_str() + str.size(), &root, &err);
      if(ret == false)
      {
        std::cout << err << std::endl;
        return false;
      }
      return true;
    }
  };
}
